
package redbaydinelv;

import java.io.FileNotFoundException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;
import org.openmarkov.core.exception.IncompatibleEvidenceException;
import org.openmarkov.core.exception.InvalidStateException;
import org.openmarkov.core.exception.NodeNotFoundException;
import org.openmarkov.core.exception.NotEvaluableNetworkException;
import org.openmarkov.core.exception.ParserException;
import org.openmarkov.core.exception.UnexpectedInferenceException;
import org.openmarkov.core.exception.WriterException;
import org.openmarkov.core.inference.InferenceAlgorithm;
import org.openmarkov.core.model.graph.Link;
import org.openmarkov.core.model.network.EvidenceCase;
import org.openmarkov.core.model.network.Node;
import org.openmarkov.core.model.network.ProbNet;
import org.openmarkov.core.model.network.State;
import org.openmarkov.core.model.network.Variable;
import org.openmarkov.core.model.network.potential.Potential;
import org.openmarkov.core.model.network.potential.PotentialRole;
import org.openmarkov.core.model.network.potential.TablePotential;
import org.openmarkov.inference.variableElimination.VariableElimination;
import org.openmarkov.io.elvira.ElviraParser;
import org.openmarkov.io.elvira.ElviraWriter;
import org.openmarkov.io.probmodel.PGMXReader;

/**
 *
 * @author Oriana Ramirez
 */
public class c_Nodos extends m_Resultado implements Runnable{
    
    private List<Node> lNodos;
    private List<String> lEnlacesTemps;   
    private List<String> Nodo1;
    private List<String> Nodo2;
    private List<String> Observar;
    private List<String> Estado;
    private int Tiempo;
    
    List<List<m_Resultado>> llResultado;
        
    String Ruta = null; 
    String NombreRed = null;
    
    public static boolean band = false;
    
    ElviraParser elp = null;
    PGMXReader opM = null;       
        
    public c_Nodos(){}
    public void CargarDatos(List<String> Nodo1, List<String> Nodo2, List<String> Observar, List<String> Estado, int Tiempo){
        this.Nodo1 = Nodo1;
        this.Nodo2 = Nodo2;
        this.Observar = Observar;
        this.Estado = Estado;
        this.Tiempo = Tiempo;
    }
    
    public void EnlacesTemp(ProbNet auxRed){        
        List<Link<Node>> lEnlaces = auxRed.getLinks();
        lEnlacesTemps = new ArrayList<>();
        for (int i = 0; i < lEnlaces.size(); i++) {
            lEnlacesTemps.add(lEnlaces.get(i).getNode1().getName().concat(" --> ").concat(lEnlaces.get(i).getNode2().getName()));            
        }      
    }
    
    public void CargarNodo(ProbNet auxRed) {            
        lNodos = new ArrayList<>();
        lNodos = auxRed.getNodes();      
    }
    
    public State[] getEstados(String nomNodo)
    {       
        int pos = -1;
        for (int i = 0; i < lNodos.size(); i++) 
        {
            if(lNodos.get(i).getName().equals(nomNodo))
            {
                pos = i; 
            }
        } 
        if (pos >= 0){
            return lNodos.get(pos).getVariable().getStates();  
        }else{
            return null;
        }
    }
    
    public String[] getEstadosS(String nomNodo)
    {     
        int pos = -1;
        for (int i = 0; i < lNodos.size(); i++) 
        {
            if(lNodos.get(i).getName().equals(nomNodo))
            {
                pos = i; 
            }
        } 
        if (pos >= 0){
            String[] nombreEst = new String[lNodos.get(pos).getVariable().getStates().length];
            for (int i = 0; i < nombreEst.length; i++) {
                nombreEst[i] = lNodos.get(pos).getVariable().getStates()[i].getName();                
            }
            return nombreEst;  
            
        }else{
            return null;
        }
    }
        
    public List<String> getEnlaces(){
        return lEnlacesTemps;
    }
    
    public List<List<m_Resultado>> getListResultados(){
        return llResultado;
    }   
      
    public List<Node> getLNodos(){
        return lNodos;         
    }   
    
    public void LeerRedEstatica(String ruta) {                
        ProbNet RedEst = null;
        Ruta = ruta.substring(0, 1 + ruta.lastIndexOf("\\")).concat("archivoTemp.elv");       
        String tipo_arch = ruta.substring(1 + ruta.lastIndexOf("."), ruta.length());         
        
        try {
            if(tipo_arch.compareTo("elv") == 0){
                elp = new ElviraParser();
                RedEst = elp.loadProbNet(ruta).getProbNet();
                NombreRed = RedEst.getName().toUpperCase();
            }else if(tipo_arch.compareTo("pgmx") == 0){
                opM = new PGMXReader();
                RedEst = opM.loadProbNet(ruta).getProbNet();  
                NombreRed = RedEst.getName().toUpperCase();
            }         
                        
            ElviraWriter estatica1 = new ElviraWriter();
            try {
                estatica1.writeProbNet(Ruta, RedEst);
            } catch (WriterException ex) {
                Logger.getLogger(c_Nodos.class.getName()).log(Level.SEVERE, null, ex);
            }
            CargarNodo(RedEst);
            EnlacesTemp(RedEst);            
            
        } catch (FileNotFoundException | ParserException ex) {
            JOptionPane.showMessageDialog(null, "Hubo un error al cargar la red o puede estar dañada, intente de nuevo");
        }        
    } 
        
    public HashMap<Variable, TablePotential> Inferencia(List<String> lsNodo, List<String> lsEstado, ProbNet RedInf){        
        InferenceAlgorithm variableElimination = null;    
        EvidenceCase evidencia;        
        HashMap<Variable, TablePotential> posteriorProbabilities = null;
        
        try {
            variableElimination = new VariableElimination(RedInf); 
            evidencia = new EvidenceCase();
            for (int i = 0; i < lsNodo.size(); i++) {
                try {
                    evidencia.addFinding(RedInf, lsNodo.get(i), lsEstado.get(i));
                } catch (NodeNotFoundException | InvalidStateException ex) {
                    Logger.getLogger(c_Nodos.class.getName()).log(Level.SEVERE, null, ex);
                }                
            }                                        
            variableElimination.setPreResolutionEvidence(evidencia);           
            posteriorProbabilities = variableElimination.getProbsAndUtilities();
                        
        } catch (NotEvaluableNetworkException | IncompatibleEvidenceException | UnexpectedInferenceException ex) {        
            Logger.getLogger(c_Nodos.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        return posteriorProbabilities;
    }      

    @Override
    public void run() {
        band = false;
        llResultado = new ArrayList<>();
        List<Node> listVarObs = new ArrayList<>();
        ProbNet RedAux2 = new ProbNet();        
        try {
            try {
                elp = new ElviraParser();
                RedAux2 = elp.loadProbNet(Ruta).getProbNet();
            } catch (FileNotFoundException ex) {
                Logger.getLogger(c_Nodos.class.getName()).log(Level.SEVERE, null, ex);
            }            
        } catch (ParserException ex) {
            Logger.getLogger(c_Nodos.class.getName()).log(Level.SEVERE, null, ex);
        }
        listVarObs = RedAux2.getNodes();
        for(int m = 0; m < Nodo1.size(); m++){
            for(int n = 0; n < listVarObs.size(); n++){
                if(listVarObs.get(n).getName().compareTo(Nodo1.get(m)) == 0){
                    listVarObs.remove(n);
                } 
            }
        }
        for(int m = 0; m < Observar.size(); m++){
            for(int l = 0; l < listVarObs.size(); l++){
                if(listVarObs.get(l).getName().compareTo(Observar.get(m)) == 0){
                    listVarObs.remove(l);
                } 
            }
        }        
        for (int k = 0; k < Tiempo; k++) {
            List<m_Resultado> lResultado = new ArrayList<>();
            ProbNet RedAux1 = new ProbNet();
            try {
                RedAux1 = elp.loadProbNet(Ruta).getProbNet();
            } catch (ParserException ex) {
                Logger.getLogger(c_Nodos.class.getName()).log(Level.SEVERE, null, ex);
            }            
            HashMap<Variable, TablePotential> probPos = Inferencia(Observar, Estado, RedAux1);             
            for (int l = 0; l < listVarObs.size(); l++) {
                m_Resultado Resultado = new m_Resultado();                 
                Resultado.setVariableTemporal(listVarObs.get(l).getName());
                Resultado.setEstados(getEstados(listVarObs.get(l).getName()));
                try {   
                    double[] aux = new double[probPos.get(RedAux1.getVariable(listVarObs.get(l).getName())).getValues().length];
                    for (int i = 0; i < aux.length; i++) {
                        BigDecimal big = new BigDecimal(probPos.get(RedAux1.getVariable(listVarObs.get(l).getName())).getValues()[i]);
                        aux[i] = big.setScale(4, RoundingMode.HALF_UP).doubleValue();
                    }
                    Resultado.setValores(aux);                    
                } catch (NodeNotFoundException ex) {
                    Logger.getLogger(c_Nodos.class.getName()).log(Level.SEVERE, null, ex);
                }
                lResultado.add(Resultado);                
                for(int c = 0; c < Nodo2.size(); c++){
                    if(listVarObs.get(l).getName().compareTo(Nodo2.get(c)) == 0){
                        TablePotential pot;
                        try {
                            pot = new TablePotential(PotentialRole.POLICY, RedAux1.getNode(Nodo1.get(c)).getVariable());
                            pot.setValues(Resultado.getValores());
                            Potential p = pot.copy();

                            RedAux1.removePotentials(RedAux1.getNode(Nodo1.get(c)));
                            RedAux1.getNode(Nodo1.get(c)).addPotential(p);

                        } catch (NodeNotFoundException ex) {
                            Logger.getLogger(c_Nodos.class.getName()).log(Level.SEVERE, null, ex);
                        }
                        break;
                    }
                }
            } 
            llResultado.add(lResultado); 
            ElviraWriter temporal1 = new ElviraWriter();
            try {
                temporal1.writeProbNet(Ruta, RedAux1);
            } catch (WriterException ex) {
                Logger.getLogger(c_Nodos.class.getName()).log(Level.SEVERE, null, ex);
            }
            try{
                Thread.sleep( 5 );
            }
            catch (InterruptedException e){
                System.err.println( e.getMessage() );
            }
        }
        band = true;
    }

}
